/*
 * AIS常见问题
 * - 一个基于 Java 的库，用于解码来自数字 VHF 无线电业务相关的 AIS 消息
 * 根据 ITU 1371 对海上航行和安全的要求。
 *
 * （C） 版权所有 2011- S-Consult ApS，增值税号。DK31327490，丹麦。
 *
 * 根据 Creative Commons 署名-非商业性使用-相同方式共享 3.0 未本地化版本许可发布。
 * 有关此许可证的详细信息，请参阅附近的 LICENCE-full 文件，请访问 http://creativecommons.org/licenses/by-nc-sa/3.0/
 * 或写信至 Creative Commons， 171 Second Street， Suite 300， San Francisco， California， 94105， USA。
 *
 * 不得用于商业用途！
 * 请联系 Thomas Borg Salling <tbsalling@tbsalling.dk>以获取此软件的商业许可版本。
 *
 */

package com.xx.dk.tbsalling.aismessages.ais.messages;

import com.xx.dk.tbsalling.aismessages.ais.messages.types.AISMessageType;
import com.xx.dk.tbsalling.aismessages.ais.messages.types.PositionFixingDevice;
import com.xx.dk.tbsalling.aismessages.ais.messages.types.SOTDMACommunicationState;
import com.xx.dk.tbsalling.aismessages.nmea.exceptions.InvalidMessage;
import com.xx.dk.tbsalling.aismessages.nmea.messages.NMEAMessage;

import java.lang.ref.WeakReference;

import static com.xx.dk.tbsalling.aismessages.ais.Decoders.*;
import static java.lang.String.format;
/**
 * 此消息供固定位置基站用于定期报告位置和时间参考。
 * @author tbsalling
 *
 */
@SuppressWarnings("serial")
public class BaseStationReport extends AISMessage {

    public BaseStationReport(NMEAMessage[] nmeaMessages) {
        super(nmeaMessages);
    }

    protected BaseStationReport(NMEAMessage[] nmeaMessages, String bitString) {
        super(nmeaMessages, bitString);
    }

    @Override
    protected void checkAISMessage() {
        super.checkAISMessage();

        final StringBuffer errorMessage = new StringBuffer();

        final int numberOfBits = getNumberOfBits();

        if (numberOfBits != 168)
            errorMessage.append(String.format("Message of type %s should be at exactly 168 bits long; not %d.", getMessageType(), numberOfBits));

        if (errorMessage.length() > 0) {
            if (numberOfBits >= 38)
                errorMessage.append(format(" Assumed sourceMmsi: %d.", getSourceMmsi().getMMSI()));

            throw new InvalidMessage(errorMessage.toString());
        }
    }

    public final AISMessageType getMessageType() {
        return AISMessageType.BaseStationReport;
    }

    @SuppressWarnings("unused")
	public Integer getYear() {
        return getDecodedValue(() -> year, value -> year = value, () -> Boolean.TRUE, () -> UNSIGNED_INTEGER_DECODER.apply(getBits(38, 52)));
	}

    @SuppressWarnings("unused")
	public Integer getMonth() {
        return getDecodedValue(() -> month, value -> month = value, () -> Boolean.TRUE, () -> UNSIGNED_INTEGER_DECODER.apply(getBits(52, 56)));
	}

    @SuppressWarnings("unused")
	public Integer getDay() {
        return getDecodedValue(() -> day, value -> day = value, () -> Boolean.TRUE, () -> UNSIGNED_INTEGER_DECODER.apply(getBits(56, 61)));
	}

    @SuppressWarnings("unused")
	public Integer getHour() {
        return getDecodedValue(() -> hour, value -> hour = value, () -> Boolean.TRUE, () -> UNSIGNED_INTEGER_DECODER.apply(getBits(61, 66)));
	}

    @SuppressWarnings("unused")
	public Integer getMinute() {
        return getDecodedValue(() -> minute, value -> minute = value, () -> Boolean.TRUE, () -> UNSIGNED_INTEGER_DECODER.apply(getBits(66, 72)));
	}

    @SuppressWarnings("unused")
	public Integer getSecond() {
        return getDecodedValue(() -> second, value -> second = value, () -> Boolean.TRUE, () -> UNSIGNED_INTEGER_DECODER.apply(getBits(72, 78)));
	}

    @SuppressWarnings("unused")
	public Boolean getPositionAccurate() {
        return getDecodedValue(() -> positionAccurate, value -> positionAccurate = value, () -> Boolean.TRUE, () -> BOOLEAN_DECODER.apply(getBits(78, 79)));
	}

    @SuppressWarnings("unused")
	public Float getLatitude() {
        return getDecodedValue(() -> latitude, value -> latitude = value, () -> Boolean.TRUE, () -> FLOAT_DECODER.apply(getBits(107, 134)) / 600000f);
	}

    @SuppressWarnings("unused")
	public Float getLongitude() {
        return getDecodedValue(() -> longitude, value -> longitude = value, () -> Boolean.TRUE, () -> FLOAT_DECODER.apply(getBits(79, 107)) / 600000f);
	}

    @SuppressWarnings("unused")
	public PositionFixingDevice getPositionFixingDevice() {
        return getDecodedValue(() -> positionFixingDevice, value -> positionFixingDevice = value, () -> Boolean.TRUE, () -> PositionFixingDevice.fromInteger(UNSIGNED_INTEGER_DECODER.apply(getBits(134, 138))));
	}

    @SuppressWarnings("unused")
	public Boolean getRaimFlag() {
        return getDecodedValue(() -> raimFlag, value -> raimFlag = value, () -> Boolean.TRUE, () -> BOOLEAN_DECODER.apply(getBits(148, 149)));
	}

    @SuppressWarnings("unused")
    public SOTDMACommunicationState getCommunicationState() {
        return getDecodedValueByWeakReference(() -> communicationState, value -> communicationState = value, () -> Boolean.TRUE, () -> SOTDMACommunicationState.fromBitString(getBits(149, 168)));
    }

    @Override
    public String toString() {
        return "BaseStationReport{" +
                "messageType=" + getMessageType() +
                ", year=" + getYear() +
                ", month=" + getMonth() +
                ", day=" + getDay() +
                ", hour=" + getHour() +
                ", minute=" + getMinute() +
                ", second=" + getSecond() +
                ", positionAccurate=" + getPositionAccurate() +
                ", latitude=" + getLatitude() +
                ", longitude=" + getLongitude() +
                ", positionFixingDevice=" + getPositionFixingDevice() +
                ", raimFlag=" + getRaimFlag() +
                ", communicationState=" + getCommunicationState() +
                "} " + super.toString();
    }

    private transient Integer year;
    private transient Integer month;
    private transient Integer day;
    private transient Integer hour;
    private transient Integer minute;
    private transient Integer second;
    private transient Boolean positionAccurate;
    private transient Float latitude;
    private transient Float longitude;
    private transient PositionFixingDevice positionFixingDevice;
    private transient Boolean raimFlag;
    private transient WeakReference<SOTDMACommunicationState> communicationState;
}
